/*
 * Copyright (C) 2008
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.sca4idea.references;

import com.intellij.openapi.util.TextRange;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PsiElementPattern;
import static com.intellij.patterns.XmlPatterns.*;
import com.intellij.psi.PsiElement;

import java.util.ArrayList;
import java.util.List;

/**
 * Utility for registering reference providers.
 *
 * @author paul.jones
 */
public final class SCAReferencesUtil {
    public static PsiElementPattern<? extends PsiElement, ?> componentElementDetailAttribute(String tagName, String attrName) {
        return xmlAttributeValue().withLocalName(attrName).withParent(
                    xmlAttribute().withParent(
                        xmlTag().withName(tagName).withParent(
                            xmlTag().withName("component").withParent(xmlTag().withName("composite"))
                        )
                    )
                );
    }

    public static PsiElementPattern<? extends PsiElement, ?> componentElementDetailAttribute(
            ElementPattern<String> tagPattern, String attrName) {
        return xmlAttributeValue().withLocalName(attrName).withParent(
                    xmlAttribute().withParent(
                        xmlTag().withName(tagPattern).withParent(
                            xmlTag().withName("component").withParent(xmlTag().withName("composite"))
                        )
                    )
                );
    }

    // TODO: This does not appear to be working yet. Suggestions welcome...
    public static ElementPattern<? extends PsiElement> implementationBody(String tagName) {
        return xmlText().withParent(xmlTag().withName(tagName).withParent(xmlTag().withName("component")));
    }

    public static ElementPattern<? extends PsiElement> compositeElementDetailAttribute(String tagName, String attrName) {
        return xmlAttributeValue().withLocalName(attrName).withParent(
                    xmlAttribute().withParent(
                        xmlTag().withName(tagName).withParent(
                            xmlTag().withName("composite")
                        )
                    )
                );
    }

    public static TextRange getAllRange(String s) {
        return new TextRange(1, s.length() + 1);
    }

    /**
     * Splits the given string into a series of text ranges, for use in the reference providers.
     * @param s the string to split.
     * @return the ranges.
     */
    public static TextRange[] splitRanges(String s) {
        if (s.trim().length() == 0) {
            return new TextRange[] { new TextRange(1, s.length() + 1) };
        }

        List<TextRange> result = new ArrayList<TextRange>();
        int pos = 0;
        int nextSpace;
        while ((nextSpace = findNextSpace(s, pos)) != -1) {
            if (s.substring(pos, nextSpace).trim().length() > 0) {
                result.add(new TextRange(pos + 1, nextSpace + 1));
            }

            pos = nextSpace + 1;
        }

        if (pos < s.length()) {
            if (s.substring(pos, s.length()).trim().length() > 0) {
                result.add(new TextRange(pos + 1, s.length() + 1));
            }
        }

        return result.toArray(new TextRange[result.size()]);
    }

    /**
     * Discovers the next space available in the given string, starting at the given position.
     * @param s the string to search.
     * @param pos the position to look in.
     * @return the string.
     */
    private static int findNextSpace(String s, int pos) {
        int space = s.indexOf(" ", pos);
        int nl = s.indexOf("\n", pos);

        // If we can't find either, return -1
        if (space == -1 && nl == -1) {
            return -1;
        }

        // If one or the other is -1, the return the other
        if (space == -1) return nl;
        if (nl == -1) return space;

        // Return the smaller one
        if (space < nl) {
            return space;
        } else {
            return nl;
        }
    }
}
